package ink.xiaobaibai.controller.monthly;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import ink.xiaobaibai.annotation.InsidePublicResources;
import ink.xiaobaibai.autoConfig.roleResources.ResourcesRoleMapping;
import ink.xiaobaibai.bo.AddLogisticsBo;
import ink.xiaobaibai.bo.AddReturnAmountBo;
import ink.xiaobaibai.common.MyRole;
import ink.xiaobaibai.entity.*;
import ink.xiaobaibai.enumOxy.DepositStatus;
import ink.xiaobaibai.enumOxy.MonthlyfeeOrderStatus;
import ink.xiaobaibai.enumOxy.ReturnDepositStatus;
import ink.xiaobaibai.multipleClick.ForbidMultipleClick;
import ink.xiaobaibai.response.ResponseFormat;
import ink.xiaobaibai.service.*;
import ink.xiaobaibai.service.monthly.IOrderProcedureService;
import ink.xiaobaibai.serviceOxy.ISmsService;
import ink.xiaobaibai.units.MySecurity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description: 退款业务接口
 * @author: 小白白
 * @create: 2021-06-04
 **/

@Api(tags = "押金业务接口")
@RestController
@RequestMapping("/deposit")
@InsidePublicResources
@CrossOrigin
public class DepositController {

    @Autowired
    private IMonthlyfeeOrderService monthlyfeeOrderService;

    @Autowired
    private IMonthlyfeeDepositService depositService;

    @Autowired
    private IMonthlyRefundDepositService refundDepositService;

    @Autowired
    private ILogisticsService logisticsService;

    @Autowired
    private IMonthlyfeeDeviceService deviceService;

    @Autowired
    private IAdminUserService adminUserService;

    @Autowired
    private IOrderProcedureService orderProcedureService;

    @Autowired
    private ISmsService smsService;

    /**
     * 业务员查看自己负责的押金退款订单
     */
    @GetMapping("/one/list")
    @ApiOperation("查看自己所负责的订单有没有退款的")
    public ResponseFormat getReturnDepositList() {
        Integer userId = MySecurity.getUserId();
        QueryWrapper<MonthlyfeeOrder> q1 = new QueryWrapper<>();
        q1.select("order_id", "user_id", "order_amount", "expire_time", "device_id", "status", "deposit_id");
        q1.eq("admin_user_id", userId);
        q1.eq("status", MonthlyfeeOrderStatus.APDEPOSIT.getStatus());
        List<MonthlyfeeOrder> list = this.monthlyfeeOrderService.list(q1);
        // 押金多少钱 退回金额是多少 创建时间
        List<String> ids = list.stream().map(l -> l.getOrderId()).collect(Collectors.toList());
        QueryWrapper<MonthlyRefundDeposit> q2 = new QueryWrapper<>();
        q2.in("order_id", ids);
        List<MonthlyRefundDeposit> listByIds = this.refundDepositService.list(q2);
        for (MonthlyfeeOrder monthlyfeeOrder : list) {
            for (MonthlyRefundDeposit listById : listByIds) {
                if (listById.getOrderId().equals(monthlyfeeOrder.getOrderId())) {
                    // 将错就错
                    monthlyfeeOrder.setExpireTime(listById.getCreateTime());
                    monthlyfeeOrder.setReturnAmount(listById.getAmount());
                    break;
                }
            }
        }
        return ResponseFormat.success(list);
    }

    @GetMapping("/return-monthly")
    @ApiOperation("传入回收费用(可选,默认0)+回收图片凭证(可选)")
    public ResponseFormat returnMonthly(@RequestParam("logisticsId") Integer logisticsId,
                                        @RequestParam("imageUrl") String imageUrl,
                                        @RequestParam("cost") BigDecimal cost) {
        UpdateWrapper<Logistics> u1 = new UpdateWrapper<>();
        u1.set("income_cost", cost);
        u1.set("images_uri2", imageUrl);
        u1.eq("id", logisticsId);
        this.logisticsService.update(u1);
        return ResponseFormat.success();
    }

    /**
     * 业务员查看当前订单的详细
     * 订单表 押金表 物流表 退款表
     */
    @GetMapping("/one/item")
    @ApiOperation("业务员查看当前退款订单的详细")
    public ResponseFormat getOrderItem(@RequestParam("orderId") String orderId) {
        /**
         * 查询是否为退款订单
         */
        MonthlyfeeOrder order = this.monthlyfeeOrderService.getById(orderId);
        if (!order.getStatus().equals(MonthlyfeeOrderStatus.APDEPOSIT.getStatus())) {
            return ResponseFormat.fail("当前订单非退款订单");
        }
        if (!MySecurity.isPower(MyRole.POWER_MONTHLY)) {
            if (!order.getAdminUserId().equals(MySecurity.getUserId())) {
                return ResponseFormat.fail("不可查看他人订单");
            }
        }
        JSONObject jsonObject = this.orderItem(order);
        return ResponseFormat.success(jsonObject);
    }

    /**
     * 业务员审核
     * 为退款表填写退款金额
     */
    @PostMapping("/one/addReturnAmount")
    @ApiOperation("业务员为押金退款订单填写退款金额(仓库管理员也可以写)")
    @ForbidMultipleClick(key = "#addReturnAmountBo.depositId")
    public ResponseFormat addReturnAmount(@RequestBody AddReturnAmountBo addReturnAmountBo) {
        String depositId = addReturnAmountBo.getDepositId();
        MonthlyfeeDeposit deposit = this.depositService.getById(depositId);
        if (deposit == null) {
            return ResponseFormat.fail("用户已取消申请");
        }
        //防止横向
        if (!MySecurity.isPower(MyRole.POWER_MONTHLY)) {
            if (!this.validMyDevice(deposit.getDeviceId())) {
                return ResponseFormat.fail("对应押金记录不存在或非自己订单");
            }
        }
        if (!deposit.getStatus().equals(DepositStatus.APPLYING.getStatus())) {
            return ResponseFormat.fail("填写失败,当前押金表状态:" + deposit.getStatus());
        }
        //可以填写,但是要验证金额
        if (addReturnAmountBo.getAmount().doubleValue() > deposit.getAmount().doubleValue()) {
            return ResponseFormat.fail("退款金额不可大于押金");
        }
        //填写金额
        UpdateWrapper<MonthlyRefundDeposit> u1 = new UpdateWrapper<>();
        u1.set("amount", addReturnAmountBo.getAmount());
        u1.eq("deposit_id", addReturnAmountBo.getDepositId());
        this.refundDepositService.update(u1);
        return ResponseFormat.success();
    }

    /**
     * 业务员审核
     * 录入物流
     */
    @PostMapping("/one/addLogistics")
    @ApiOperation("业务员为押金订单填写回来的物流信息(仓库管理员也可以写)")
    public ResponseFormat addLogistics(@RequestBody AddLogisticsBo addLogisticsBo) {
        String depositId = addLogisticsBo.getDepositId();
        MonthlyfeeDeposit deposit = this.depositService.getById(depositId);
        if (deposit == null) {
            return ResponseFormat.fail("用户已取消申请");
        }
        //防止横向
        if (!MySecurity.isPower(MyRole.POWER_MONTHLY)) {
            if (!this.validMyDevice(deposit.getDeviceId())) {
                return ResponseFormat.fail("对应押金记录不存在或非自己订单");
            }
        }
        //是否已经存在物流 存在修改即可 不存在 保存 订单表+退款表 放入id
        QueryWrapper<MonthlyRefundDeposit> q1 = new QueryWrapper<>();
        q1.select("logistics_id");
        q1.eq("deposit_id", depositId);
        MonthlyRefundDeposit refundDeposit = this.refundDepositService.getOne(q1);
        Integer logisticsId = refundDeposit.getLogisticsId();
        UpdateWrapper<Logistics> u1 = new UpdateWrapper<>();
        u1.set("images_uri2", addLogisticsBo.getImageUri());
        u1.set("income_cost", addLogisticsBo.getIncomeCost());
        u1.eq("id", logisticsId);
        this.logisticsService.update(u1);
        return ResponseFormat.success();
    }

    /**
     * 业务员提交确认
     * 需传入押金表id 与客户端对应
     */
    @PostMapping("/one/confirm")
    @ApiOperation("业务员提交确认")
    @ForbidMultipleClick(key = "#depositId")
    public ResponseFormat confirmOne(@RequestParam("depositId") String depositId) {
        //取消状态会直接删除
        //修改退款表状态即可
        //如果没有填写退款金额，那么就不可确认
        QueryWrapper<MonthlyRefundDeposit> q1 = new QueryWrapper<>();
        q1.eq("deposit_id", depositId);
        MonthlyRefundDeposit monthlyRefundDeposit = this.refundDepositService.getOne(q1);
        if (monthlyRefundDeposit.getAmount() == null) {
            return ResponseFormat.fail("请填写退款金额");
        }
        String role = MySecurity.getRole();
        UpdateWrapper<MonthlyRefundDeposit> u1 = new UpdateWrapper<>();
        if (MySecurity.isPower(MyRole.POWER_MONTHLY)) {
            u1.eq("deposit_id", depositId);
            u1.set("status", ReturnDepositStatus.THREE.getStatus());
            this.refundDepositService.update(u1);
            // 直接就去退款了
            this.confirmThree(depositId);
        } else if (role.equals(MyRole.AGENT)) {
            u1.set("status", ReturnDepositStatus.THREE.getStatus());
            u1.eq("deposit_id", depositId);
            this.refundDepositService.update(u1);
            this.smsService.oaSms(1, "退押金");
        } else {
            u1.set("status", ReturnDepositStatus.TWO.getStatus());
            Integer depId = this.adminUserService.getDepId(MySecurity.getUserId());
            AdminUser user = this.adminUserService.getAgentIdByDepId(depId);
            u1.eq("deposit_id", depositId);
            this.refundDepositService.update(u1);
            this.smsService.oaSms(user.getId(), "退押金");
        }
        return ResponseFormat.success();
    }

    /**
     * 经理查看退款订单列表
     */
    @GetMapping("/two/list")
    @ApiOperation("经理查看自己所部门有没有退款的")
    public ResponseFormat getReturnDepositListWithAgent() {
        if (!MySecurity.getRole().equals(MyRole.AGENT)) {
            return ResponseFormat.fail("仅经理可操作");
        }
        Integer userId = MySecurity.getUserId();
        Integer depId = this.adminUserService.getDepId(userId);
        QueryWrapper<MonthlyfeeOrder> q1 = new QueryWrapper<>();
        q1.select("order_id", "user_id", "order_amount", "expire_time", "device_id", "status");
        q1.eq("status", MonthlyfeeOrderStatus.APDEPOSIT.getStatus());
        q1.eq("admin_dep_id", depId);
        List<MonthlyfeeOrder> list = this.monthlyfeeOrderService.list(q1);
        // 押金多少钱 退回金额是多少 创建时间
        List<String> ids = list.stream().map(l -> l.getOrderId()).collect(Collectors.toList());
        QueryWrapper<MonthlyRefundDeposit> q2 = new QueryWrapper<>();
        q2.in("order_id", ids);
        List<MonthlyRefundDeposit> listByIds = this.refundDepositService.list(q2);
        for (MonthlyfeeOrder monthlyfeeOrder : list) {
            for (MonthlyRefundDeposit listById : listByIds) {
                if (listById.getOrderId().equals(monthlyfeeOrder.getOrderId())) {
                    // 将错就错
                    monthlyfeeOrder.setExpireTime(listById.getCreateTime());
                    monthlyfeeOrder.setReturnAmount(listById.getAmount());
                    break;
                }
            }
        }
        return ResponseFormat.success(list);
    }

    /**
     * 经理查看当前退款审核订单详细
     */
    @GetMapping("/two/item")
    @ApiOperation("经理查看退款订单详细")
    public ResponseFormat getAgentList(@RequestParam("orderId") String orderId) {
        /**
         * 查询是否为退款订单
         */
        if (!MySecurity.getRole().equals(MyRole.AGENT)) {
            return ResponseFormat.fail("仅经理可操作");
        }
        Integer userId = MySecurity.getUserId();
        Integer depId = this.adminUserService.getDepId(userId);
        MonthlyfeeOrder order = this.monthlyfeeOrderService.getById(orderId);
        if (!order.getStatus().equals(MonthlyfeeOrderStatus.APDEPOSIT.getStatus())) {
            return ResponseFormat.fail("当前订单非退款订单");
        }
        if (!order.getAdminDepId().equals(depId)) {
            return ResponseFormat.fail("不可查看其他部门的订单");
        }
        JSONObject jsonObject = this.orderItem(order);
        return ResponseFormat.success(jsonObject);
    }

    /**
     * 经理通过审核
     */
    @PostMapping("/two/confirm")
    @ApiOperation("经理通过审核(传入押金订单号)")
    @ForbidMultipleClick(key = "#depositId")
    public ResponseFormat confirmTwo(@RequestParam("depositId") String depositId) {
        String role = MySecurity.getRole();
        if (!role.equals(MyRole.AGENT)) {
            return ResponseFormat.fail("仅经理可操作");
        }
        Integer userId = MySecurity.getUserId();
        Integer depId = this.adminUserService.getDepId(userId);

        QueryWrapper<MonthlyRefundDeposit> q0 = new QueryWrapper<>();
        q0.eq("deposit_id", depositId);
        MonthlyRefundDeposit refundDeposit = this.refundDepositService.getOne(q0);
        if (refundDeposit == null) {
            return ResponseFormat.fail("当前押金不存在");
        }
        String status = refundDeposit.getStatus();
        if (!status.equals(ReturnDepositStatus.TWO.getStatus())) {
            return ResponseFormat.fail("业务员未通过");
        }
        String orderId = refundDeposit.getOrderId();
        MonthlyfeeOrder order = this.monthlyfeeOrderService.getById(orderId);
        if (!order.getStatus().equals(MonthlyfeeOrderStatus.APDEPOSIT.getStatus())) {
            return ResponseFormat.fail("当前订单非退款订单");
        }
        if (!order.getAdminDepId().equals(depId)) {
            return ResponseFormat.fail("不可查看其他部门的订单");
        }
        UpdateWrapper<MonthlyRefundDeposit> q1 = new UpdateWrapper<>();
        q1.set("status", ReturnDepositStatus.THREE.getStatus());
        q1.eq("deposit_id", depositId);
        this.refundDepositService.update(q1);
        this.smsService.oaSms(1, "押金退款");
        return ResponseFormat.success();
    }

    /**
     * 管理查看系统的退款订单
     */
    @GetMapping("/three/list")
    @ApiOperation("管理查看当前系统的退款订单")
    @ResourcesRoleMapping(resourceName = "管理员看退款订单", includeRoleNames = {MyRole.ADMIN, MyRole.POWER_MONTHLY})
    public ResponseFormat getReturnDepositListWithAdmin() {
        QueryWrapper<MonthlyfeeOrder> q1 = new QueryWrapper<>();
        q1.eq("status", MonthlyfeeOrderStatus.APDEPOSIT.getStatus());
        q1.select("order_id", "user_id", "order_amount", "expire_time", "device_id", "status");
        List<MonthlyfeeOrder> list = this.monthlyfeeOrderService.list(q1);
        // 押金多少钱 退回金额是多少 创建时间
        List<String> ids = list.stream().map(l -> l.getOrderId()).collect(Collectors.toList());
        QueryWrapper<MonthlyRefundDeposit> q2 = new QueryWrapper<>();
        q2.in("order_id", ids);
        List<MonthlyRefundDeposit> listByIds = this.refundDepositService.list(q2);
        for (MonthlyfeeOrder monthlyfeeOrder : list) {
            for (MonthlyRefundDeposit listById : listByIds) {
                if (listById.getOrderId().equals(monthlyfeeOrder.getOrderId())) {
                    // 将错就错
                    monthlyfeeOrder.setExpireTime(listById.getCreateTime());
                    monthlyfeeOrder.setReturnAmount(listById.getAmount());
                    break;
                }
            }
        }
        return ResponseFormat.success(list);
    }

    /**
     * 管理查看当前订单详细
     */
    @GetMapping("/three/item")
    @ApiOperation("管理员查看当前订单详细")
    @ResourcesRoleMapping(resourceName = "管理员看退款订单详细", includeRoleNames = {MyRole.ADMIN, MyRole.POWER_MONTHLY})
    public ResponseFormat getItemWithAdmin(@RequestParam("orderId") String orderId) {
        MonthlyfeeOrder order = this.monthlyfeeOrderService.getById(orderId);
        if (!order.getStatus().equals(MonthlyfeeOrderStatus.APDEPOSIT.getStatus())) {
            return ResponseFormat.fail("当前订单非退款订单");
        }
        JSONObject jsonObject = this.orderItem(order);
        return ResponseFormat.success(jsonObject);
    }

    /**
     * 管理员修改退款金额
     */
    @PutMapping("/three/amount")
    @ApiOperation("管理员修改退款金额")
    @ForbidMultipleClick(key = "#addReturnAmountBo.depositId")
    @ResourcesRoleMapping(resourceName = "管理员修改退款金额", includeRoleNames = {MyRole.ADMIN, MyRole.POWER_MONTHLY})
    public ResponseFormat updateAmount(@RequestBody AddReturnAmountBo addReturnAmountBo) {
        String depositId = addReturnAmountBo.getDepositId();
        MonthlyfeeDeposit deposit = this.depositService.getById(depositId);
        if (addReturnAmountBo.getAmount().doubleValue() > deposit.getAmount().doubleValue()) {
            return ResponseFormat.fail("退款金额不可大于押金");
        }
        //验证金额
        if (!deposit.getStatus().equals(DepositStatus.APPLYING.getStatus())) {
            return ResponseFormat.fail("填写失败,当前押金表状态:" + deposit.getStatus());
        }
        //填写金额
        UpdateWrapper<MonthlyRefundDeposit> u1 = new UpdateWrapper<>();
        u1.eq("deposit_id", addReturnAmountBo.getDepositId());
        u1.set("amount", addReturnAmountBo.getAmount());
        this.refundDepositService.update(u1);
        return ResponseFormat.success();
    }

    /**
     * 管理员通过审核,开始退款
     */
    @PostMapping("/three/confirm")
    @ApiOperation("管理员通过审核")
    @ForbidMultipleClick(key = "#depositId")
    @ResourcesRoleMapping(resourceName = "管理员通过退款审核", includeRoleNames = {MyRole.ADMIN, MyRole.POWER_MONTHLY})
    public ResponseFormat confirmThree(@RequestParam("depositId") String depositId) {
        // todo 未修正,前端传来的是订单ID,前端需要修正成押金ID
        //先确认押金订单状态
        MonthlyfeeDeposit deposit = this.depositService.getById(depositId);
        if (!deposit.getStatus().equals(DepositStatus.APPLYING.getStatus())) {
            //非退还中,说明用户已经取消了申请
            return ResponseFormat.fail("用户已取消申请退款");
        }
        QueryWrapper<MonthlyRefundDeposit> q1 = new QueryWrapper<>();
        q1.eq("deposit_id", deposit.getOrderId());
        // 给管理权限
//        MonthlyRefundDeposit refundDeposit = refundDepositService.getOne(q1);
//        if(!refundDeposit.getStatus().equals(ReturnDepositStatus.THREE.getStatus())){
//            return ResponseFormat.fail("经理未审核,不可通过");
//        }
        MonthlyRefundDeposit monthlyRefundDeposit = this.refundDepositService.getOne(q1);
        if (monthlyRefundDeposit.getAmount() == null) {
            return ResponseFormat.fail("请填写退款金额");
        }
        //修改退款表,里面已经写完了
        this.orderProcedureService.okDepositReturn(deposit);
        return ResponseFormat.success();
    }

    /**
     * 取消当前押金
     */
    @PostMapping("/delete-deposit")
    @ApiOperation("删除当前押金 || 消除当前押金记录")
    @ResourcesRoleMapping(resourceName = "管理员删除押金", includeRoleNames = {MyRole.ADMIN, MyRole.POWER_MONTHLY})
    public ResponseFormat delete(@RequestBody String depositId) {
        this.depositService.removeById(depositId);
        return ResponseFormat.success();
    }

    /**
     * 取消当前退款申请
     */
    @PostMapping("/cancel-refund-deposit")
    @ApiOperation("取消当前退款申请")
    @ResourcesRoleMapping(resourceName = "管理员取消退款审核", includeRoleNames = {MyRole.ADMIN, MyRole.POWER_MONTHLY})
    public ResponseFormat cancel(@RequestBody String refundId) {
        this.refundDepositService.removeById(refundId);
        return ResponseFormat.success();
    }

    private boolean validMyDevice(Integer deviceId) {
        /**
         * 查询对应机器是不是自己的不就行了
         */
        QueryWrapper<MonthlyfeeDevice> q1 = new QueryWrapper<>();
        q1.eq("id", deviceId);
        q1.eq("admin_user_id", MySecurity.getUserId());
        return this.deviceService.count(q1) != 0;
    }

    /**
     * 记住客户端锁的是押金表主键
     * 不止防一起点,并且进入锁之后一定要判断表中状态(避免当前页面停留太久,然后再操作)
     */

    private JSONObject orderItem(MonthlyfeeOrder order) {
        //物流表
        Integer logisticsId = order.getLogisticsId();
        Logistics logistics = this.logisticsService.getById(logisticsId);

        //押金表
        QueryWrapper<MonthlyfeeDeposit> q1 = new QueryWrapper<>();
        q1.eq("order_id", order.getDepositId());
        MonthlyfeeDeposit deposit = this.depositService.getOne(q1);

        //退款表
        QueryWrapper<MonthlyRefundDeposit> q2 = new QueryWrapper<>();
        q2.eq("deposit_id", order.getDepositId());
        MonthlyRefundDeposit refundDeposit = this.refundDepositService.getOne(q2);

        //直接一个JSONObject
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("order", order);
        jsonObject.put("logistics", logistics);
        jsonObject.put("deposit", deposit);
        jsonObject.put("refundDeposit", refundDeposit);
        return jsonObject;
    }

}
